home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
276-300
/
disk_280
/
graph
/
grph.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
55KB
|
1,825 lines
/*
* GRAPH, Version 1.00 - 4 August 1989
*
* Copyright 1989, David Gay. All Rights Reserved.
* This software is freely redistrubatable.
*/
/* Graph manipulation */
#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <graphics/rastport.h>
#include <intuition/intuition.h>
#include <devices/prtbase.h>
#include <devices/printer.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include <iff/iff.h>
#include <iff/ilbm.h>
#include "grph.h"
#include "file.h"
#include "graphics.h"
#include "graph.h"
#include "uio.h"
#include "object.h"
#include "list.h"
#include "coords.h"
#include "user/gadgets.h"
#include "tracker.h"
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/diskfont.h>
#include <proto/intuition.h>
#define INCH 2.54e-2
#define DIGHEIGHT 8 /* Digit font size, in points (1 point = 1/72 inch) */
#define XTICK 0.05 /* Size of tick for X axis, In inches */
#define YTICK 0.05
#define XTEXT 0.12
#define YTEXT 0.09
#define MAXPRINTPAGES 1 /* Max length for printing */
#define CHOOSELIST 2 /* for choose req */
#define IFFDISK 2 /* For iff req */
/* A function to send a slice of output to the chosen device (disk/file) */
typedef int (*prtfunc)(struct graph *g, struct RastPort *rp, int w, int h, int
y, int slice, struct Requester *abreq);
extern struct GfxBase *GfxBase;
static UWORD scr_dpmx, scr_dpmy; /* The screen 'resolution' */
/* Data for printer output */
static struct IODRPReq *prtio;
static struct MsgPort *prtport;
static struct PrinterExtendedData *ped;
static struct Preferences *prtprefs;
static struct ColorMap *prtcm;
/* Data for iff output */
static FILE *iff_file;
static long form_pos, body_pos;
static char iff_filename[FILELEN];
static struct Gadget *iffg;
static char *prt_error[] = {
"Unknown error",
"Print cancelled",
"Not a graphics printer !",
"Obsolete",
"Illegal print dimensions",
"Obsolete",
"No memory (internal)",
"No memory (for buffers)"
};
#define MAX_PRT_ERROR (sizeof(prt_error) / sizeof(char *) - 1)
/* Check that ax can be displayed */
static int ax_ok(const struct ax *a, const struct ax *other)
{
return (a->ax == NOVAL ||
((!other->log || a->ax > 0.0) &&
(a->cstep == NOVAL ||
(a->cstep > 0.0 &&
(a->every == INOVAL || a->every > 0)))));
}
/* Check that ax has legal values */
static int ax_ok2(const struct ax *a)
{
return a->min != NOVAL && a->max != NOVAL && a->min < a->max &&
(!a->log || a->min > 0.0);
}
/* Check if graph is displayable */
static int graph_ok(struct graph *g)
{
g->a.ok = ax_ok(&g->a.x, &g->a.y) && ax_ok(&g->a.y, &g->a.x) &&
(g->a.ratio == NOVAL || g->a.ratio > 0.0);
return ax_ok2(&g->a.x) && ax_ok2(&g->a.x);
}
/* Redraw graph after changes */
static void check_graph(struct graph *g)
{
g->saved = FALSE;
g->ok = graph_ok(g);
set_scale(g);
draw_graph(g, TRUE);
}
/* Find object in graph by name */
static struct object *find_object(struct graph *g, char *name)
{
struct object *o;
for (o = first(&g->o_list); succ(o); o = succ(o))
if (strcmp(o->name, name) == 0) return o;
return NULL;
}
/* Convert inches to rastport dots, using current dpm */
/* Use integer arithmetic if needs to be called often */
int xinch2dots(struct graph *g, double x)
{
return (int)(x * INCH * g->io.dpmx + 0.5);
}
int yinch2dots(struct graph *g, double y)
{
return (int)(y * INCH * g->io.dpmy + 0.5);
}
/* Open font in pts points */
struct TextFont *open_font(struct graph *g, char *name, int pts, int style, int
flags)
{
struct TextAttr ta;
struct TextFont *tf1, *tf2;
ta.ta_Name = name;
ta.ta_YSize = yinch2dots(g, pts / 72.0);
ta.ta_Style = style;
ta.ta_Flags = flags;
tf1 = OpenFont(&ta);
if (!tf1)
return OpenDiskFont(&ta);
else if (tf1->tf_YSize != ta.ta_YSize)
{
tf2 = OpenDiskFont(&ta);
if (tf2)
{
CloseFont(tf1);
return tf2;
}
else
return tf2;
}
else
return tf1;
}
/* add object to graph (object is already displayed) */
struct object *add_object(struct graph *g, struct object *o)
{
if (o)
{
if (o->name[0] != '\0' && find_object(g, o->name))
{
message(g, "Name already used", (char *)NULL);
refresh_graph(g, TRUE, o->delete(o));
return NULL;
}
add_head(&g->o_list, o);
g->saved = FALSE;
}
return o;
}
/* Remove object & redisplay graph */
void remove_object(struct graph *g, struct object *o)
{
if (o == g->s.current)
{
o->deselect(o);
g->s.current = NULL;
disable_rect_menus(g);
disable_object_menus(g);
}
remove(o);
g->saved = FALSE;
refresh_graph(g, TRUE, o->delete(o));
}
/* Make object o selected */
void select_object(struct graph *g, struct object *o)
{
if (o)
{
g->s.current = o;
o->select(o); /* Inform object of this */
enable_object_menus(g);
set_title(g);
}
}
/* Deslect current object */
void deselect(struct graph *g)
{
struct Region *ref;
/* Deselect object */
ref = g->s.current ? g->s.current->deselect(g->s.current) : NULL;
g->s.current = NULL;
disable_rect_menus(g);
disable_object_menus(g);
refresh_graph(g, TRUE, ref);
}
/* User pressed mouse button */
void mouse_down(struct graph *g, WORD sx, WORD sy)
{
if (g->ok && g->io.rw)
{
/* Get real pos */
g->s.x = g->io.rw->x(g->io.rw, sx);
g->s.y = g->io.rw->y(g->io.rw, sy);
/* If nothing selected, or if not clicking in selected object */
if (!g->s.current || !g->s.current->down(g->s.current))
{
deselect(g);
if (g->s.select_mode) /* Try to select something */
{
struct object *o;
for (o = first(&g->o_list); succ(o); o = succ(o))
if (o->down(o)) /* Inside object ? */
{
select_object(g, o);
break; /* exit for loop */
}
}
else /* Start a new rectangle */
if (g->s.current = (struct object *)new_pos(g))
enable_rect_menus(g);
}
if (g->s.current) /* Something is now selected, keep track of mouse */
{
/* Adjust position for offset in object */
g->s.x = g->io.rw->x(g->io.rw, sx - g->s.current->mx);
g->s.y = g->io.rw->y(g->io.rw, sy - g->s.current->my);
ReportMouse(g->io.win, TRUE);
g->s.mouse = TRUE;
}
set_title(g);
}
}
/* Mouse has moved */
void mouse_move(struct graph *g, WORD sx, WORD sy)
{
if (g->s.mouse)
{
/* Adjust for offset, calc pos in coord system */
sx -= g->s.current->mx;
sy -= g->s.current->my;
g->s.x = g->io.rw->x(g->io.rw, sx);
g->s.y = g->io.rw->y(g->io.rw, sy);
/* Inform selection of movement */
g->s.current->move(g->s.current);
set_title(g);
}
}
/* Mouse button released */
void mouse_up(struct graph *g, WORD sx, WORD sy)
{
if (g->s.mouse) /* mouse was down */
{
g->saved = FALSE; ./* Graph has very probably changed */
g->s.mouse = FALSE;
sx -= g->s.current->mx;
sy -= g->s.current->my;
g->s.x = g->io.rw->x(g->io.rw, sx);
g->s.y = g->io.rw->y(g->io.rw, sy);
ReportMouse(g->io.win, FALSE);
/* Redaw whatever is necessary */
refresh_graph(g, TRUE, g->s.current->up(g->s.current));
}
}
/* Handler for object selection requester */
static int choose_handler(struct Gadget *gg, ULONG class, struct Requester *req
, struct graph *g)
{
if (gg->GadgetID == CHOOSELIST) /* In a list */
{
if (ModifyList(gg, req, req->RWindow, class == GADGETUP) == 2)
{
EndRequest(req, req->RWindow);
return TRUE;
}
}
else return std_ghandler(gg, class, req, g);
}
/* Ask user to choose an object, by name */
struct object *choose_object(struct graph *g, char *op)
{
struct object *o, *sel = NULL;
char name[FNAMELEN];
tlist l;
char what[30];
int ok;
/* Construct title */
what[29] = '\0'; name[0] = '\0';
strncpy(what, op, 29);
strncat(what, " function", 29 - strlen(what));
/* Construct list of named objects */
new_list(&l);
ok = TRUE;
for (o = first(&g->o_list); succ(o); o = succ(o))
if (o->name[0] != '\0')
{
tnode *n = alloc_node(sizeof(tnode));
if (!n)
{
ok = FALSE;
break;
}
n->ln_Name = o->name;
add_tail(&l, n);
}
if (ok) /* list constructed ok */
{
/* Create requester */
struct Requester *req;
struct Memory *m;
struct Gadget *gl = NULL;
if ((m = NewMemory()) &&
(req = InitReq(50, 20, 200, 120, m)) &&
SetReqBorder(req, 1, m) &&
AddIntuiText(&req->ReqText, what, 100 - 4 * strlen(what), 6, m) &&
AddList(&gl, CHOOSELIST, "Name", &l, name, FNAMELEN, 0, RELVERIFY |
ENDGADGET, 20, 20, 160, 80, TRUE, m) &&
AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 18, 95, 65, 15, F
ALSE, m) &&
AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 118, 95, 65,
15, FALSE, m))
{
SetReqGadgets(req, gl);
if (DoRequest(req, g, choose_handler))
{
/* Remove blanks */
strip(name);
if (*name)
{
sel = find_object(g, name);
if (!sel) message(g, "No such function", (char *)NULL);
}
}
}
Free(m);
}
free_list((list *)&l, sizeof(tnode));
return sel;
}
/* Define coordinate system */
void enter_limits(struct graph *g)
{
struct Requester *req;
struct Memory *m;
struct Gadget *gl = NULL, *x_log, *y_log;
char xmin[NBLEN], xmax[NBLEN], ymin[NBLEN], ymax[NBLEN], ratio[NBLEN];
double2str(xmin, g->a.x.min);
double2str(xmax, g->a.x.max);
double2str(ymin, g->a.y.min);
double2str(ymax, g->a.y.max);
double2str(ratio, g->a.ratio);
if ((m = NewMemory()) &&
(req = InitReq(50, 20, 325, 105, m)) &&
SetReqBorder(req, 1, m) &&
AddIntuiText(&req->ReqText, "Limits", 138, 6, m) &&
AddText(&gl, 0, "X: Min ", FALSE, xmin, NBLEN, TRUE, 0, RELVERIFY, 67,
20, 80, 10, TRUE, m) &&
AddText(&gl, 0, "Max ", FALSE, xmax, NBLEN, TRUE, 0, RELVERIFY, 190, 20
, 80, 10, TRUE, m) &&
(x_log = AddOption(&gl, 0, "Log", FALSE, g->a.x.log * SELECTED, 0, 305,
20, 10, 10, m)) &&
AddText(&gl, 0, "Y: Min ", FALSE, ymin, NBLEN, TRUE, 0, RELVERIFY, 67,
40, 80, 10, TRUE, m) &&
AddText(&gl, 0, "Max ", FALSE, ymax, NBLEN, TRUE, 0, RELVERIFY, 190, 40
, 80, 10, TRUE, m) &&
(y_log = AddOption(&gl, 0, "Log", FALSE, g->a.y.log * SELECTED, 0, 305,
40, 10, 10, m)) &&
AddText(&gl, 0, "Ratio (Y/X) ", FALSE, ratio, NBLEN, TRUE, 0, RELVERIFY
, 107, 60, 80, 10, TRUE, m) &&
AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 49, 80, 65, 15, FALSE
, m) &&
AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 211, 80, 65, 15,
FALSE, m))
{
SetReqGadgets(req, gl);
if (DoRequest(req, g, std_ghandler))
{
g->a.x.min = str2double(xmin);
g->a.x.max = str2double(xmax);
g->a.x.log = (x_log->Flags & SELECTED) != 0;
g->a.y.min = str2double(ymin);
g->a.y.max = str2double(ymax);
g->a.y.log = (y_log->Flags & SELECTED) != 0;
g->a.ratio = str2double(ratio);
check_graph(g);
}
}
Free(m);
}
/* Choose axes display options */
void enter_axes(struct graph *g)
{
struct Requester *req;
struct Memory *m;
struct Gadget *gl = NULL;
char ax_x[NBLEN], ax_y[NBLEN], step_x[NBLEN], step_y[NBLEN],
every_x[INTLEN], every_y[INTLEN];
double2str(ax_x, g->a.x.ax);
double2str(step_x, g->a.x.cstep);
int2str(every_x, g->a.x.every);
double2str(ax_y, g->a.y.ax);
double2str(step_y, g->a.y.cstep);
int2str(every_y, g->a.y.every);
if ((m = NewMemory()) &&
(req = InitReq(50, 15, 225, 165, m)) &&
SetReqBorder(req, 1, m) &&
AddIntuiText(&req->ReqText, "Axes", 96, 6, m) &&
AddText(&gl, 0, "X: Axe at ", FALSE, ax_x, NBLEN, TRUE, 0, RELVERIFY, 9
1, 20, 80, 10, TRUE, m) &&
AddText(&gl, 0, " Ticks every ", FALSE, step_x, NBLEN, TRUE, 0, RELVE
RIFY, 131, 40, 80, 10, TRUE, m) &&
AddText(&gl, 0, " numbered every ", FALSE, every_x, INTLEN, TRUE, 0,
RELVERIFY, 155, 60, 32, 10, TRUE, m) &&
AddText(&gl, 0, "Y: Axe at ", FALSE, ax_y, NBLEN, TRUE, 0, RELVERIFY, 9
1, 80, 80, 10, TRUE, m) &&
AddText(&gl, 0, " Ticks every ", FALSE, step_y, NBLEN, TRUE, 0, RELVE
RIFY, 131, 100, 80, 10, TRUE, m) &&
AddText(&gl, 0, " numbered every ", FALSE, every_y, INTLEN, TRUE, 0,
RELVERIFY, 155, 120, 32, 10, TRUE, m) &&
AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 24, 140, 65, 15, FALS
E, m) &&
AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 136, 140, 65, 15
, FALSE, m))
{
SetReqGadgets(req, gl);
if (DoRequest(req, g, std_ghandler))
{
g->a.x.ax = str2double(ax_x);
g->a.x.cstep = str2double(step_x);
g->a.x.every = str2int(every_x);
g->a.y.ax = str2double(ax_y);
g->a.y.cstep = str2double(step_y);
g->a.y.every = str2int(every_y);
check_graph(g);
}
}
Free(m);
}
/* Change mode */
void set_mode(struct graph *g, int newmode)
{
if (newmode != g->s.select_mode) deselect(g);
g->s.select_mode = newmode;
}
/* Recalc & display title */
/* assumes GNAMELEN < TITLELEN */
void set_title(struct graph *g)
{
strcpy(g->io.title, g->name);
if (!g->ok) strncat(g->io.title, "(Bad)", TITLELEN - 1 - strlen(g->io.title
));
if (g->s.current)
if (g->s.current->name[0] != '\0')
{
strncat(g->io.title, ", function is ", TITLELEN - 1 - strlen(g->io.
title));
strncat(g->io.title, g->s.current->name, TITLELEN - 1 - strlen(g->i
o.title));
if (!g->s.current->ok) strncat(g->io.title, "(Bad)", TITLELEN - 1 -
strlen(g->io.title));
}
else strncat(g->io.title, ", object selected", TITLELEN -1 - strlen(g->
io.title));
else strncat(g->io.title, ", nothing selected", TITLELEN - 1 - strlen(g->io
.title));
if (g->s.mouse)
{
char x[NBLEN], y[NBLEN];
double2str(x, g->s.x); double2str(y, g->s.y);
strncat(g->io.title, " x=", TITLELEN - 1 - strlen(g->io.title));
strncat(g->io.title, x, TITLELEN - 1 - strlen(g->io.title));
strncat(g->io.title, ", y=", TITLELEN - 1 - strlen(g->io.title));
strncat(g->io.title, y, TITLELEN - 1 - strlen(g->io.title));
}
SetWindowTitles(g->io.win, g->io.title, "Graph");
}
/* Window has changed size, recreate coord system, taking into account the
desired ratio */
void set_scale(struct graph *g)
{
/* Standard borders */
long x0offset = g->io.win->BorderLeft + 8;
long x1offset = g->io.win->BorderRight + 8;
long y0offset = g->io.win->BorderBottom + 8;
long y1offset = g->io.win->BorderTop + 8;
/* Save size used */
g->io.oldwidth = g->io.win->Width; g->io.oldheight = g->io.win->Height;
/* Delete old coords */
if (g->io.rw) g->io.rw->delete(g->io.rw);
/* Create new coords at max size */
g->io.rw = new_RWindow(g->io.win->RPort, g->io.win->Width, g->io.win->Heigh
t,
x0offset, y0offset, x1offset, y1offset,
g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
g->a.x.log, g->a.y.log, TRUE);
if (!g->io.rw)
{
message(g, "Couldn't make coords", (char *)NULL);
return;
}
SetRast(g->io.win->RPort, 0); /* Clear whole window */
if (g->ok && g->a.ok && g->a.ratio != NOVAL)
{
/* Adjust for desired ratio */
double r;
/* Current ratio */
r = g->a.ratio /
fabs(((g->io.rw->sy(g->io.rw, g->a.y.log ? 10.0 : 2.0) - g->io.rw->
sy(g->io.rw, 1.0)) * scr_dpmx) /
((g->io.rw->sx(g->io.rw, g->a.x.log ? 10.0 : 2.0) - g->io.rw->
sx(g->io.rw, 1.0)) * scr_dpmy));
g->io.rw->delete(g->io.rw);
/* Adjust borders */
if (r > 1.0) /* make X smaller */
{
long width = g->io.win->Width - x0offset - x1offset;
long delta = width - width / r;
x0offset += delta / 2;
x1offset += delta - delta / 2;
}
else /* make Y smaller */
{
long height = g->io.win->Height - y0offset - y1offset;
long delta = height - height * r;
y0offset += delta / 2;
y1offset += delta - delta / 2;
}
/* & create new coord system */
g->io.rw = new_RWindow(g->io.win->RPort, g->io.win->Width, g->io.win->H
eight,
x0offset, y0offset, x1offset, y1offset,
g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
g->a.x.log, g->a.y.log, TRUE);
if (!g->io.rw)
{
message(g, "Couldn't make coords", (char *)NULL);
return;
}
}
}
/* Change output resolution.
This may require opening of new resources (eg fonts) in the objects, which
can obviously fail, yet we don't want the graph to be left in an inconsis-
tent state, hence inform & confirm (cf object.guidelines). */
int set_dpm(struct graph *g, int dpmx, int dpmy)
{
int olddpmx = g->io.dpmx, olddpmy = g->io.dpmy;
struct TextFont *digits;
g->io.dpmx = dpmx; g->io.dpmy = dpmy;
/* Open correct font for this resolution */
if (digits = open_font(g, "digits.font", DIGHEIGHT, 0, 0))
{
int ok = TRUE;
struct object *scan, *scan2;
/* Inform objects */
for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
if (!scan->inform(scan)) ok = FALSE;
if (ok)
{
/* Everything worked, confoirm changes */
for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
scan->confirm(scan, TRUE);
/* Free old resources */
CloseFont(g->io.digits);
g->io.digits = digits;
return TRUE;
}
/* Return to previous state */
for (scan2 = first(&g->o_list); scan2 != scan; scan2 = succ(scan2))
scan2->confirm(scan2, FALSE);
CloseFont(digits);
}
else
message(g, "Couldn't open digits.font", (char *)NULL);
g->io.dpmx = olddpmx; g->io.dpmy = olddpmy;
return FALSE;
}
/* Set pen to one ptsize wide. Should really modify g->io.rw->rp, but ... *
/
void set_pensize(struct graph *g, struct RastPort *rp, double ptsize)
{
int xsize = xinch2dots(g, ptsize / 72.0);
int ysize = yinch2dots(g, ptsize / 72.0);
if ((xsize & 1) == 0) xsize++;
if ((ysize & 1) == 0) ysize++;
rp->PenWidth = xsize;
rp->PenHeight = ysize;
}
/* Use a "thin" line (1 pixel wide) */
void set_thin(struct graph *g, struct RastPort *rp)
{
rp->PenWidth = 1;
rp->PenWidth = 1;
}
/* Change graph limits */
void zoom_in(struct graph *g, double x0, double y0, double x1, double y1)
{
if (g->ok && x0 != x1 && y0 != y1)
{
double xmin = min(x0, x1);
double xmax = max(x0, x1);
double ymin = min(y0, y1);
double ymax = max(y0, y1);
g->a.x.min = max(g->a.x.min, xmin);
g->a.x.max = min(g->a.x.max, xmax);
g->a.y.min = max(g->a.y.min, ymin);
g->a.y.max = min(g->a.y.max, ymax);
check_graph(g);
}
else
message(g, "No rectangle to zoom into", (char *)NULL);
}
/* Calculate new limits for ax a for a zoom factor of mult */
static void zoom_ax(struct ax *a, double mult)
{
if (a->log)
{
/* Zoom on a log scale ... Real fun with this one :-) */
double centre = sqrt(a->min * a->max);
double delta = pow(centre, 1.0 - mult);
a->min = pow(a->min, mult) * delta;
a->max = pow(a->max, mult) * delta;
}
else
{
/* ax becomes mult times longer, with same centre */
double centre = (a->min + a->max) / 2;
double delta = centre - a->min;
a->min = centre - mult * delta;
a->max = centre + mult * delta;
}
}
/* Zoom out by a factor factor */
void zoom_factor(struct graph *g, double factor)
{
if (g->ok)
{
zoom_ax(&g->a.x, factor);
zoom_ax(&g->a.y, factor);
check_graph(g);
}
else
message(g, "No scale set !", (char *)NULL);
}
/* Define new centre for ax */
static void center_ax(struct ax *a, double centre)
{
if (a->log)
{
/* more & more fun ... */
double delta = sqrt(a->max / a->min);
a->max = centre * delta;
a->min = centre / delta;
}
else
{
/* obvious */
double delta = (a->max - a->min) / 2.0;
a->max = centre + delta;
a->min = centre - delta;
}
}
/* New centre for graph */
void center_graph(struct graph *g, double x, double y)
{
if (g->ok && x != NOVAL)
{
center_ax(&g->a.x, max(min(x, g->a.x.max), g->a.x.min));
center_ax(&g->a.y, max(min(y, g->a.y.max), g->a.y.min));
check_graph(g);
}
else
message(g, "Nothing to center on", (char *)NULL);
}
/* Redraw ax a (of graph g), at position xorig on other ax. y_ax is true for
drawing of y axis */
static void draw_ax(struct graph *g, struct ax *a, double xorig, int y_ax)
{
struct TextFont *oldfont, *digits = g->io.digits;
struct RWindow *const rwin = g->io.rw;
struct RastPort *const rp = rwin->rp;
int xtick = yinch2dots(g, XTICK), ytick = xinch2dots(g, YTICK);
int xtext = xinch2dots(g, XTEXT), ytext = yinch2dots(g, YTEXT);
oldfont = rp->Font;
SetFont(rp, digits);
SetDrMd(rp, JAM1);
if (a->ax != NOVAL)
{
/* Draw ax */
if (y_ax)
{
RMove(rwin, a->ax, a->max);
Draw(rwin->rp, rwin->rp->cp_x, ftol(rwin->sy(rwin, a->min)));
}
else
{
RMove(rwin, a->max, a->ax);
Draw(rwin->rp, ftol(rwin->sx(rwin, a->min)), rwin->rp->cp_y);
}
if (a->cstep != NOVAL)
{
/* Draw ticks and numbers */
if (a->log)
{
/* logarithmic ax */
double nax;
int emin, emax, e, count, i;
/* Normalise origin (0 < nax < 10). There will be count ticks,
at nax, nax + cstep, nax + 2 * cstep, etc for every exponent
value between min & max */
nax = xorig * pow(10.0, -floor(log10(xorig)));
/* Exponent range */
emin = floor(log10(a->min / nax));
emax = ceil(log10(a->max / nax));
/* Number of ticks for every exponent value */
count = ceil(9 * nax / a->cstep);
for (e = emin; e <= emax; e++)
{
double const p = pow(10.0, (double)e);
double const st = a->cstep * p; /* step between ticks */
double x = p * nax; /* POos. of main tick */
long cx, cy;
/* Display main value (at nax, with exponent) */
if (a->every != INOVAL && x != xorig)
{
if (y_ax)
RMove(rwin, a->ax, x);
else
RMove(rwin, x, a->ax);
cx = rp->cp_x; cy = rp->cp_y;
if (e == 0)
{
/* don't display 10^0 */
char nb[NBLEN];
int l;
/* Display nax */
double2str(nb, nax);
l = strlen(nb);
if (y_ax)
Move(rp, cx + xtext, cy + digits->tf_Baseline /
2);
else
Move(rp, cx - digits->tf_XSize * l / 2, cy + di
gits->tf_Baseline + ytext);
Text(rp, nb, l);
}
else
{
char nb[NBLEN + 3], expo[NBLEN];
int l1, l2;
if (nax == 1)
strcpy(nb, "10");
else
{
double2str(nb, nax);
strcat(nb, "*10");
}
sprintf(expo, "%d", e);
l1 = strlen(nb);
l2 = strlen(expo);
/* Display base */
if (y_ax)
Move(rp, cx + xtext, cy + digits->tf_Baseline /
2);
else
Move(rp, cx, cy + digits->tf_Baseline + digits-
>tf_Baseline / 2 + ytext);
Text(rp, nb, l1);
/* Display exponent */
Move(rp, rp->cp_x, rp->cp_y - digits->tf_Baseline /
2);
Text(rp, expo, l2);
}
}
/* Now for the ticks ... */
for (i = 0; i < count; i++, x += st)
{
/* Draw tick */
if (y_ax)
RMove(rwin, a->ax, x);
else
RMove(rwin, x, a->ax);
cx = rp->cp_x; cy = rp->cp_y;
if (y_ax)
{
Move(rp, cx + ytick, cy);
Draw(rp, cx - ytick, cy);
}
else
{
Move(rp, cx, cy + xtick);
Draw(rp, cx, cy - xtick);
}
/* Display digits */
if (i != 0 && a->every != INOVAL && (i % a->every) == 0
)
{
char nb[NBLEN];
int l;
/* Only display mantissa */
double2str(nb, nax + i * a->cstep);
l = strlen(nb);
if (y_ax)
Move(rp, cx + xtext, cy + digits->tf_Baseline /
2);
else
Move(rp, cx - digits->tf_XSize * l / 2 + 1, cy
+ digits->tf_Baseline + ytext);
Text(rp, nb, l);
}
}
}
}
else
{
/* linear ax */
long count, disp_digits;
double x;
/* Number of ticks */
count = ceil((a->min - xorig) / a->cstep);
/* First tick at which to show value */
disp_digits = a->every == INOVAL ?
count - 1 : /* No digits displayed */
a->every * (long)ceil((a->min - xorig) / (a->cs
tep * a->every));
for(x = count * a->cstep + xorig; x <= a->max; x += a->cstep, c
ount++)
{
long cx, cy;
/* Draw tick */
if (y_ax)
RMove(rwin, a->ax, x);
else
RMove(rwin, x, a->ax);
cx = rp->cp_x; cy = rp->cp_y;
if (y_ax)
{
Move(rp, cx + ytick, cy);
Draw(rp, cx - ytick, cy);
}
else
{
Move(rp, cx, cy + xtick);
Draw(rp, cx, cy - xtick);
}
/* Display digits */
if (count == disp_digits)
{
char nb[NBLEN];
int l;
/* Next one in every ticks */
disp_digits += a->every;
if (count != 0) /* Not at origin */
{
double2str(nb, x);
l = strlen(nb);
if (y_ax)
Move(rp, cx + xtext, cy + digits->tf_Baseline /
2);
else
Move(rp, cx - digits->tf_XSize * l / 2, cy + di
gits->tf_Baseline + ytext);
Text(rp, nb, l);
}
}
}
}
}
}
SetFont(rp, oldfont);
}
/* Draws directly into the rastport, used internally. allow_mes nust be FALSE
if called during window refresh */
static void do_draw(struct graph *g, int allow_mes)
{
struct object *o;
if (g->ok && g->io.rw)
{
/* Draw axes */
SetAPen(g->io.rw->rp, 1L);
if (g->a.ok)
{
draw_ax(g, &g->a.x, g->a.y.ax, FALSE);
draw_ax(g, &g->a.y, g->a.x.ax, TRUE);
}
/* Draw objects */
for (o = first(&g->o_list); succ(o); o = succ(o))
if (o != g->s.current && o->ok) o->draw(o, allow_mes);
/* Current object is always last so that it appears "on top" */
if (g->s.current && g->s.current->ok) g->s.current->draw(g->s.current,
allow_mes);
}
}
/* Redraw graph completely */
void draw_graph(struct graph *g, int allow_mes)
{
if (allow_mes) set_title(g);
SetRast(g->io.rw->rp, 0); /* Clear window */
do_draw(g, allow_mes);
}
/* Redraw graph partially (ref is NULL for no redraw). ref is disposed when
refresh is done */
void refresh_graph(struct graph *g, int allow_mes, struct Region *ref)
{
if (ref)
{
if (g->io.rw)
{
/* Setup clipping */
struct Region *oldRegion = InstallClipRegion(g->io.rw->rp->Layer, r
ef);
SetRast(g->io.rw->rp, 0);
do_draw(g, allow_mes);
InstallClipRegion(g->io.rw->rp->Layer, oldRegion);
}
DisposeRegion(ref);
}
}
/* Returns a region that will fully refresh g.
(makes a copy of the current region) */
struct Region *full_refresh(struct graph *g)
{
struct Region *r;
if ((r = NewRegion()) && g->io.rw)
{
struct Region *old = InstallClipRegion(g->io.rw->rp->Layer, NULL);
/* Make copy */
if (!OrRegionRegion(old, r))
{
DisposeRegion(r);
r = NULL;
}
InstallClipRegion(g->io.rw->rp->Layer, old);
}
return r;
}
/* Open printer.device */
static int open_prt(void)
{
if (prtport = CreatePort(0L, 0L))
{
if (prtio = (struct IODRPReq *)CreateExtIO(prtport, sizeof(struct IODRP
Req)))
{
if (OpenDevice("printer.device", 0, (struct IORequest *)prtio, 0) =
= 0)
{
ped = &((struct PrinterData *)prtio->io_Device)->pd_SegmentData
->ps_PED;
prtprefs = &((struct PrinterData *)prtio->io_Device)->pd_Prefer
ences;
return TRUE;
}
DeleteExtIO((struct IORequest *)prtport);
}
DeletePort(prtport);
}
return FALSE;
}
/* Close printer device */
static void close_prt(void)
{
CloseDevice((struct IORequest *)prtio);
DeleteExtIO((struct IORequest *)prtio);
DeletePort(prtport);
}
/* Easy access to DumpRPort. wait : DoIO or SendIO ? */
static void prt_raster(int wait, struct RastPort *rp, struct ColorMap *cm, ULON
G m, UWORD sx, UWORD sy, UWORD w, UWORD h, LONG dc, LONG dr, UWORD special)
{
prtio->io_RastPort = rp;
prtio->io_ColorMap = cm;
prtio->io_Modes = m;
prtio->io_SrcX = sx;
prtio->io_SrcY = sy;
prtio->io_SrcWidth = w;
prtio->io_SrcHeight = h;
prtio->io_DestCols = dc;
prtio->io_DestRows = dr;
prtio->io_Special = special;
prtio->io_Command = PRD_DUMPRPORT;
if (wait) DoIO(prtio);
else SendIO(prtio);
}
/* Print a slice of the dump to the printer */
static int prt_slice(struct graph *g, struct RastPort *rp, int w, int h, int y,
int slice, struct Requester *abreq)
{
struct RWindow *old = g->io.rw;
int ret = FALSE;
ULONG prtsig = 1 << prtio->io_Message.mn_ReplyPort->mp_SigBit;
ULONG winsig = 1 << g->io.win->UserPort->mp_SigBit;
/* Create coords for slice */
g->io.rw = new_RWindow(rp, w, slice,
0, y + slice - h, 0, -y,
g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
g->a.x.log, g->a.y.log, FALSE);
if (g->io.rw)
{
int done = FALSE;
/* Draw into rastport. Note that it may be > 1024 x 1024 ! */
BigSetRast(rp, 0);
do_draw(g, TRUE);
prt_raster(FALSE, rp, prtcm, 0L, 0, 0, (UWORD)w, (UWORD)slice, w, slice
, SPECIAL_NOFORMFEED);
do { /* Wait for end of printing or abort */
Wait(prtsig | winsig);
if (aborted(abreq))
{
done = TRUE;
ret = FALSE; /* Stop! */
if (!CheckIO(prtio))
{
AbortIO(prtio);
WaitIO(prtio);
}
prtio->io_Error = 0;
}
else if (CheckIO(prtio))
{
done = TRUE;
ret = prtio->io_Error == 0;
}
} while (!done);
g->io.rw->delete(g->io.rw);
}
else
nomem(g->io.win);
g->io.rw = old;
return ret;
}
/* Work out the max size for a slice (don't use more than half the largest
chunk of chip ram). The height must be a multiple of quanta */
static int get_slice_height(int w, int h, int quanta)
{
long use = AvailMem(MEMF_CHIP | MEMF_LARGEST) / 2;
long min = 2 * RASSIZE(w, quanta);
long nb = use / min;
if (nb == 0) /* Not much mem ... */ return quanta;
else if (nb * quanta > h) return h;
else return nb * quanta;
}
/* Create a 2 plane Rastport with clipping at its limits (-> Layer) */
static struct RastPort *alloc_ras(int w, int h)
{
struct Layer_Info *li;
struct BitMap *bm;
BYTE *data;
struct Layer *l;
/* Alloc components */
if (li = NewLayerInfo())
{
if (bm = AllocMem(sizeof(struct BitMap), 0L))
{
if (data = AllocMem(2 * RASSIZE(w, h), MEMF_CHIP))
{
/* Set up data structure */
InitBitMap(bm, 2, w, h);
bm->Planes[0] = (PLANEPTR)data;
bm->Planes[1] = (PLANEPTR)(data + RASSIZE(w, h));
if (l = CreateUpfrontLayer(li, bm, 0, 0, w - 1, h - 1, LAYERSIM
PLE, NULL))
return l->rp;
FreeMem(data, 2 * RASSIZE(w, h));
}
FreeMem(bm, sizeof(struct BitMap));
}
DisposeLayerInfo(li);
}
return NULL;
}
/* Free rastport created by alloc_ras */
static void free_ras(struct RastPort *rp)
{
struct Layer_Info *li = rp->Layer->LayerInfo;
struct BitMap *bm = rp->BitMap;
DeleteLayer(li, rp->Layer);
FreeMem(bm->Planes[0], bm->BytesPerRow * bm->Rows * bm->Depth);
FreeMem(bm, sizeof(struct BitMap));
DisposeLayerInfo(li);
}
/* Print graph into a bitmap which is w by h pixels, resolution xdpm, ydpm,
quanta is the size of the print head (if any, 1 otherwise). dump_slice is
called for every slice.
Rem: printing is broken into horizontal slices, according to available
memory */
static void prt(struct graph *g, int w, int h, int quanta, int xdpm, int ydpm,
prtfunc dump_slice)
{
int slice, y, ok = TRUE;
struct RastPort *rp;
struct Requester *abreq;
struct Requester *req;
struct Memory *m;
struct Gadget *gl = NULL, *thin;
char size[NBLEN];
size[0] = '\0';
/* Ask user for print characteristics (pen size) */
if ((m = NewMemory()) &&
(req = InitReq(50, 20, 180, 85, m)) &&
SetReqBorder(req, 1, m) &&
AddIntuiText(&req->ReqText, "Print Characteristics", 6, 6, m) &&
(thin = AddRadio(&gl, 0, "Thin", TRUE, SELECTED, RELVERIFY, 2, 11, 20,
10, 10, m)) &&
AddRadio(&gl, 0, "Thick,", TRUE, 0, RELVERIFY, 1, 11, 40, 10, 10, m) &&
AddText(&gl, 0, "Size ", FALSE, size, NBLEN, TRUE, 0, RELVERIFY, 128, 4
1, 32, 10, TRUE, m) &&
AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 13, 60, 65, 15, FALSE
, m) &&
AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 103, 60, 65, 15,
FALSE, m))
{
SetReqGadgets(req, gl);
if (DoRequest(req, g, std_ghandler))
{
double ptsize = str2double(size);
if ((thin->Flags & SELECTED) || (ptsize > 0.0 && ptsize != NOVAL))
{
/* Set up for printing */
if (set_dpm(g, xdpm, ydpm))
{
slice = get_slice_height(w, h, quanta);
if (rp = alloc_ras(w, slice))
{
if (abreq = abort_request(g, "Printing, slice
"))
{
if (thin->Flags & SELECTED) set_thin(g, rp);
else set_pensize(g, rp, ptsize);
/* Print all the slices */
for (y = 0; ok && y < h; y += slice)
{
char msg[30];
sprintf(msg, "Printing, slice %d of %d", y / sl
ice + 1, (h + slice - 1) / slice);
set_abort_msg(abreq, msg);
ok = dump_slice(g, rp, w, h, y, min(slice, h -
y), abreq);
}
end_abort_request(abreq);
}
else
message(g, "Abort requester failed", (char *)NULL);
free_ras(rp);
}
else
nomem(g->io.win);
/* Return to screen */
set_dpm(g, scr_dpmx, scr_dpmy);
}
}
else
message(g, "Illegal line size", (char *)NULL);
}
}
Free(m);
}
/* get max size of printed output */
static int get_max_size(struct graph *g, int *w, int *h, int *quanta)
{
prt_raster(TRUE, g->io.win->RPort, prtcm, 0L, 0, 0, g->io.win->Width, g->io
.win->Height, LONG_MAX, LONG_MAX, SPECIAL_NOPRINT);
*w = prtio->io_DestCols;
*h = prtio->io_DestRows;
/* If length = infinity, use MAXPRINTPAGES pages */
if (*h == LONG_MAX)
*h = (ped->ped_YDotsInch * MAXPRINTPAGES * prtprefs->PaperLength) / (pr
tprefs->PrintSpacing == SIX_LPI ? 6 : 8);
*quanta = ped->ped_NumRows;
return prtio->io_Error == 0;
}
/* Determine size which fits asked for ratio (when no absolute size set in
preferences) */
static int get_size(struct graph *g, int *w, int *h, int *quanta)
{
if (get_max_size(g, w, h, quanta))
{
if (g->ok && g->a.ok && g->a.ratio != NOVAL)
{
/* adjust for ratio */
double r = g->a.ratio /
fabs((*h / (g->a.y.log ? log10(g->a.y.max / g->a.y.min) : (g->a
.y.max - g->a.y.min)) * ped->ped_XDotsInch) /
(*w / (g->a.x.log ? log10(g->a.x.max / g->a.x.min) : (g->a
.x.max - g->a.x.min)) * ped->ped_YDotsInch));
if (r > 1.0) /* make X smaller */
*w /= r;
else /* make Y smaller */
*h *= r;
}
if (*w == 0) *w = 1;
if (*h == 0) *h = 1;
return TRUE;
}
return FALSE;
}
/* determine size to use when user has set abs. size in preferences */
static int get_abs_size(struct graph *g, int *w, int *h, int *quanta)
{
if (get_max_size(g, w, h, quanta))
{
if (g->ok && g->a.ok && g->a.ratio != NOVAL)
{
/* Adjust only if dimension is free (size set to 0) */
double r = g->a.ratio /
fabs((*h / (g->a.y.log ? log10(g->a.y.max / g->a.y.min) : (g->a
.y.max - g->a.y.min)) * ped->ped_XDotsInch) /
(*w / (g->a.x.log ? log10(g->a.x.max / g->a.x.min) : (g->a
.x.max - g->a.x.min)) * ped->ped_YDotsInch));
if (r > 1.0 && prtprefs->PrintMaxWidth == 0) /* make X smaller */
*w /= r;
else if (r < 1.0 && prtprefs->PrintMaxHeight == 0) /* make Y smalle
r */
*h *= r;
}
if (*w == 0) *w = 1;
if (*h == 0) *h = 1;
return TRUE;
}
return FALSE;
}
/* Print a graph */
void prt_graph(struct graph *g)
{
int w, h, quanta;
if (g->ok)
if (open_prt())
{
prtprefs->PrintFlags &= ~INTEGER_SCALING; /* We produce nice output
anyway ! */
prtprefs->PrintAspect = ASPECT_HORIZ; /* No support for vertical pl
ots */
switch (prtprefs->PrintFlags & DIMENSIONS_MASK)
{
case MULTIPLY_DIMENSIONS: /* Ignored */
prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
/* FALLTHROUGH */
case IGNORE_DIMENSIONS:
case BOUNDED_DIMENSIONS:
if (get_size(g, &w, &h, &quanta))
{
prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
prt(g, w, h, quanta, (int)(ped->ped_XDotsInch / INCH),
(int)(ped->ped_YDotsInch / INCH), prt_slice);
}
break;
case ABSOLUTE_DIMENSIONS:
case PIXEL_DIMENSIONS:
if (get_abs_size(g, &w, &h, &quanta))
{
prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
prt(g, w, h, quanta, (int)(ped->ped_XDotsInch / INCH),
(int)(ped->ped_YDotsInch / INCH), prt_slice);
}
break;
}
if (prtio->io_Error > 0) /* Printer error */
message(g, "Printer Error", prt_error[prtio->io_Error > MAX_PRT
_ERROR ? 0 : prtio->io_Error], (char *)NULL);
close_prt();
}
else
message(g, "Couldn't open printer\n", (char *)NULL);
}
/* Write slice into body. Must add byteRun1 compression */
static int write_iffslice(struct BitMap *bm)
{
int y, plane;
for (y = 0; y < bm->Rows; y++)
{
/* Interleave bit planes */
for (plane = 0; plane < bm->Depth; plane++)
if (!fwrite(bm->Planes[plane] + y * bm->BytesPerRow, bm->BytesPerRo
w, 1, iff_file))
return FALSE;
}
return TRUE;
}
/* Draw & write into slice for iff output */
static int iff_slice(struct graph *g, struct RastPort *rp, int w, int h, int y,
int slice, struct Requester *abreq)
{
struct RWindow *old = g->io.rw;
int ret = FALSE;
g->io.rw = new_RWindow(rp, w, slice,
0, y + slice - h, 0, -y,
g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
g->a.x.log, g->a.y.log, FALSE);
if (g->io.rw)
{
BigSetRast(rp, 0);
do_draw(g, TRUE);
if (write_iffslice(rp->BitMap))
{
if (!aborted(abreq)) ret = TRUE;
}
else
message(g, "Error writing file", (char *)NULL);
g->io.rw->delete(g->io.rw);
}
else
nomem(g->io.win);
g->io.rw = old;
return ret;
}
/* Write ILBM header to file (BMHD, CMAP & start of BODY). Save positions for
writing sizes */
static int start_iff(char *name, int w, int h, int xdpi, int ydpi)
{
if (iff_file = fopen(name, "w"))
{
if (fwrite("FORM", 4, 1, iff_file) && (form_pos = ftell(iff_file)) != -
1L &&
fwrite("\0\0\0\0ILBMBMHD\0\0\0\024", 16, 1, iff_file))
{
static BitMapHeader bm = {
0, 0, 0, 0, 2, mskNone, cmpNone, 0, 0
};
bm.w = w; bm.h = h;
bm.xAspect = ydpi; bm.yAspect = xdpi;
bm.pageWidth = w; bm.pageHeight = h;
if (fwrite((char *)&bm, sizeof(bm), 1, iff_file) &&
fwrite("CMAP\0\0\0\14", 8, 1, iff_file) &&
fwrite("\xff\xff\xff\0\0\0\0\0\0\0\0\0", 12, 1, iff_file) &&
fwrite("BODY", 4, 1, iff_file) && (body_pos = ftell(iff_file))
!= -1 &&
fwrite("\0\0\0\0", 4, 1, iff_file))
{
return TRUE;
}
}
/* If failed, delete file */
if (fclose(iff_file) == 0) unlink(name);
}
return FALSE;
}
/* Write end of iff_file, ie pad, write lengths & close */
static int end_iff(void)
{
long end = ftell(iff_file), end2 = end;
if (end != -1)
{
if ((end & 1) == 0 || (end2++, fwrite("\0", 1, 1, iff_file))) /* pad. y
uck. */
{
long formlen = end2 - form_pos - 4; /* Includes pad byte */
long bodylen = end - body_pos - 4; /* Doesn't */
if (fseek(iff_file, form_pos, 0) != -1 &&
fwrite((char *)&formlen, sizeof(long), 1, iff_file) &&
fseek(iff_file, body_pos, 0) != -1 &&
fwrite((char *)&bodylen, sizeof(long), 1, iff_file))
{
return fclose(iff_file) == 0;
}
}
}
return FALSE;
}
/* Handle iff requester: display file req when user clicks on disk */
static int iff_handler(struct Gadget *gg, ULONG class, struct Requester *req, s
truct graph *g)
{
if (gg->GadgetID == IFFDISK)
{
char file[FILELEN];
if (getfile(file, "IFF Output file"))
{
UWORD pos = RemoveGList(req->RWindow, iffg, 1);
strcpy(iff_filename, file);
RefreshGList(iffg, req->RWindow, req, 1);
AddGList(req->RWindow, iffg, pos, 1, req);
}
ActivateGadget(iffg, req->RWindow, req);
return FALSE;
}
else return std_ghandler(gg, class, req, g);
}
/* Output graph as ILBM. Asks for bitmap size, and resolution. Ignores graph
ratio. */
void iff_todisk(struct graph *g)
{
struct Requester *req;
struct Memory *m;
struct Gadget *gl = NULL;
char xsize[NBLEN], ysize[NBLEN], xdpi[NBLEN], ydpi[NBLEN];
xsize[0] = '\0'; ysize[0] = '\0';
strcpy(xdpi, "72"); strcpy(ydpi, "72");
iff_filename[0] = '\0';
if ((m = NewMemory()) &&
(req = InitReq(50, 20, 280, 110, m)) &&
SetReqBorder(req, 1, m) &&
AddIntuiText(&req->ReqText, "Write IFF", 104, 6, m) &&
(iffg = AddText(&gl, 0, "File ", FALSE, iff_filename, FILELEN, TRUE, 0,
RELVERIFY, 51, 20, 144, 10, TRUE, m)) &&
AddBox(&gl, IFFDISK, "Disk", 0, RELVERIFY, 205, 17, 65, 15, FALSE, m) &
&
AddText(&gl, 0, "Size: X ", FALSE, xsize, INTLEN, TRUE, 0, RELVERIFY, 7
5, 45, 32, 10, TRUE, m) &&
AddText(&gl, 0, "Y ", FALSE, ysize, INTLEN, TRUE, 0, RELVERIFY, 140, 45
, 32, 10, TRUE, m) &&
AddText(&gl, 0, "DPI: X ", FALSE, xdpi, INTLEN, TRUE, 0, RELVERIFY, 83,
65, 32, 10, TRUE, m) &&
AddText(&gl, 0, "Y ", FALSE, ydpi, INTLEN, TRUE, 0, RELVERIFY, 140, 65,
32, 10, TRUE, m) &&
AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 38, 85, 65, 15, FALSE
, m) &&
AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 178, 85, 65, 15,
FALSE, m))
{
SetReqGadgets(req, gl);
if (DoRequest(req, g, iff_handler))
{
int w = str2int(xsize);
int h = str2int(ysize);
int xdp = str2int(xdpi);
int ydp = str2int(ydpi);
if (w > 0 && h > 0 && xdp > 0 && ydp > 0 &&
w != NOVAL && h != NOVAL && xdp != NOVAL && ydp != NOVAL)
if (start_iff(iff_filename, w, h, xdp, ydp))
{
prt(g, w, h, 1, (int)(xdp / INCH), (int)(ydp / INCH), iff_s
lice);
if (!end_iff())
message(g, "Error writing file", (char *)NULL);
}
else
message(g, "Error writing file", (char *)NULL);
else
message(g, "Illegal dimensions !", (char *)NULL);
}
}
Free(m);
}
/* Write graph to file f */
int save_graph(struct graph *g, FILE *f)
{
int ok = FALSE;
short tag = GRAPH_TAG;
/* Write graph information */
if (WRITE(f, tag) &&
WRITE(f, g->io.win->LeftEdge) &&
WRITE(f, g->io.win->TopEdge) &&
WRITE(f, g->io.win->Width) &&
WRITE(f, g->io.win->Height) &&
WRITE(f, g->name) &&
WRITE(f, g->a))
{
struct object *scan;
ok = TRUE;
/* Write all objects */
for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
{
if (!scan->save(scan, f)) ok = FALSE;
}
/* Write end tag */
if (ok)
{
tag = GRAPH_END;
ok = WRITE(f, tag);
g->saved = TRUE;
}
}
return ok;
}
/* Load & create new graph from file f (graph tag already read) */
struct graph *load_graph(struct graph *from, FILE *f)
{
struct graph *g = new_graph(from);
if (g)
{
WORD leftedge, topedge, width, height;
int ok = FALSE;
/* Read graph info */
if (READ(f, leftedge) &&
READ(f, topedge) &&
READ(f, width) &&
READ(f, height) &&
READ(f, g->name) &&
READ(f, g->a))
{
int done = FALSE;
ok = TRUE;
do /* Read objects */
{
short tag;
struct object *o = NULL;
if (READ(f, tag))
switch (tag) /* We have to know which objects exist ... */
{
case GRAPH_END:
done = TRUE;
break;
case LABEL_TAG:
o = (struct object *)load_label(g, f);
break;
case FUNCTION_TAG:
o = (struct object *)load_function(g, f);
break;
default:
message(g, "File is not a graph", (char *)NULL);
break;
}
ok = done || o != NULL;
if (o)
add_tail(&g->o_list, o);
} while (!done && ok);
}
if (!ok)
{
delete_graph(g);
g = NULL;
}
else /* All ok, display */
{
check_graph(g);
g->saved = TRUE;
}
}
return g;
}
/* Delete a graph */
void delete_graph(struct graph *g)
{
struct object *o, *next;
/* Deselect */
if (g->s.current) g->s.current->deselect(g->s.current);
/* Delete all objects */
for (o = first(&g->o_list); next = succ(o); o = next)
{
struct Region *ref = o->delete(o);
DisposeRegion(ref);
}
/* Delete all local resources */
if (g->io.rw) g->io.rw->delete(g->io.rw);
CloseFont(g->io.digits);
cleanup_uio(g); /* Clears menus, closes window ... */
FreeMem(g, sizeof(struct graph));
}
/* Create a new graph */
struct graph *new_graph(struct graph *from)
{
struct graph *const g = AllocMem(sizeof(struct graph), 0L);
char *msg;
const static struct graph def_g = { /* Default values */
{ NULL },
FALSE, TRUE,
"Graph",
{ MENUNULL },
{ NULL },
{
{
NOVAL, NOVAL,
NOVAL, NOVAL,
INOVAL,
FALSE
},
{
NOVAL, NOVAL,
NOVAL, NOVAL,
INOVAL,
FALSE
},
NOVAL,
FALSE, FALSE
},
{
FALSE, FALSE,
NOVAL, NOVAL,
NULL
}
};
if (g)
{
*g = def_g;
g->io.dpmx = scr_dpmx; g->io.dpmy = scr_dpmy;
new_list(&g->o_list); /* no objects */
if (g->io.digits = open_font(g, "digits.font", DIGHEIGHT, 0, 0))
{
if (init_uio(g)) /* Open window */
{
set_scale(g);
draw_graph(g, TRUE); /* & display */
return g;
}
else msg = "No window";
CloseFont(g->io.digits);
}
else msg = "digits.font missing";
FreeMem(g, sizeof(struct graph));
}
else msg = "No memory !";
message(from, "Couldn't create graph", msg, (char *)NULL);
return NULL;
}
/* Global initialisation */
int init_grph(void)
{
struct Screen wbscr;
/* Find screen resolution */
scr_dpmx = GfxBase->NormalDPMX;
scr_dpmy = GfxBase->NormalDPMY;
if (!GetScreenData((char *)&wbscr, sizeof(struct Screen), WBENCHSCREEN, NUL
L))
return alert(NULL, "No Workbench !", NULL), FALSE;
if (wbscr.ViewPort.Modes & HIRES) scr_dpmx *= 2;
if (wbscr.ViewPort.Modes & LACE) scr_dpmy *= 2;
/* Color map for printer. Add colours ? */
if (!(prtcm = GetColorMap(4))) return nomem(NULL), FALSE;
SetRGB4CM(prtcm, 0, 15, 15, 15);
SetRGB4CM(prtcm, 1, 0, 0, 0);
SetRGB4CM(prtcm, 2, 0, 0, 0);
SetRGB4CM(prtcm, 3, 0, 0, 0);
return TRUE;
}
/* Free any global resources */
void cleanup_grph(void)
{
if (prtcm) FreeColorMap(prtcm);
}